FOLIUM es una biblioteca de visualización de Python que se desarrolló con el único fin de visualizar datos geoespaciales. Es una biblioteca completamente gratuita.
Tabla de Contenido
- Acerca de los conjuntos de datos (DataFrame)
- Mapa Puntual
- Mapa de calor
- Mapa de calor con función tiempo
- Tareas a realizar
Base de datos: https://datos.madrid.es/portal/site/egob
Documentación: https://python-visualization.github.io/folium/
Alumnos:
Indicar el nombre de los alumnos responsablesEstudio de la accidentalidad de la ciudad de Madrid mediante mapa de calor y puntual.
Caso de estudio
Crear un mapa de calor y puntual de los accidentes originados por vehiculos y bicicletas en el año 2021In [3]:
#!pip install folium
#!pip install openpyxl
# Instalar previamente las librerias openpyxl
import pandas as pd
import numpy as np
import folium
from folium import plugins
import webbrowser
base_datos= pd.read_excel('2021_Accidentalidad.xlsx')
base_datos.head(5)
Out[3]:
| num_expediente | fecha | hora | localizacion | numero | cod_distrito | distrito | tipo_accidente | estado_meteorológico | tipo_vehiculo | tipo_persona | rango_edad | sexo | cod_lesividad | lesividad | coordenada_x_utm | coordenada_y_utm | positiva_alcohol | positiva_droga | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | Conductor | De 30 a 34 años | Mujer | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN |
| 1 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | Conductor | De 35 a 39 años | Hombre | 7.0 | Asistencia sanitaria sólo en el lugar del acci... | 444976.463 | 4470508.259 | N | NaN |
| 2 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | Conductor | Desconocido | Desconocido | NaN | NaN | 444976.463 | 4470508.259 | N | NaN |
| 3 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | Pasajero | De 10 a 14 años | Hombre | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN |
| 4 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | Pasajero | De 35 a 39 años | Mujer | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN |
Preparación Base de datos¶
In [5]:
print(base_datos.dtypes) # imprime el tipo de campo
print("Numero de registros =" , len( base_datos)) # imprime el tamaño de la base de datos
num_expediente object fecha datetime64[ns] hora object localizacion object numero object cod_distrito float64 distrito object tipo_accidente object estado_meteorológico object tipo_vehiculo object tipo_persona object rango_edad object sexo object cod_lesividad float64 lesividad object coordenada_x_utm float64 coordenada_y_utm float64 positiva_alcohol object positiva_droga float64 dtype: object Numero de registros = 41783
In [6]:
# Elimina los registros en blanco en los campos de coordenadas
accidentes_df = base_datos.dropna(subset=['coordenada_x_utm', 'coordenada_y_utm'])
Transformación de coordenadas¶
La geolocalización en el fichero de accidentes del ayuntamiento de Madrid se realiza con coordenadas UTM ETRS89 en el Huso 30. Para representar coordenadas en FOLIUM se necesitan coordenadas geográficas en el mismo sistema
In [7]:
#!pip install pyproj
# instalar previamente la libreria pyproj
from pyproj import Transformer
# Establecer los sistemas de transformación epsg:xxxx de entrada y epsg:yyyyy de salida
transformacion = Transformer.from_crs('epsg:25830','epsg:4258',always_xy=True)
puntos = list(zip(accidentes_df.coordenada_x_utm,accidentes_df.coordenada_y_utm)) # Crea una lista con todos los puntos
coorgeo = np.array(list(transformacion.itransform(puntos)))
accidentes_df.loc[:,'longitud'] = coorgeo[:,0]
accidentes_df.loc[:,'latitud'] = coorgeo[:,1]
accidentes_df.head()
C:\Users\hugom\AppData\Local\Temp\ipykernel_9144\718492628.py:10: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy accidentes_df.loc[:,'longitud'] = coorgeo[:,0] C:\Users\hugom\AppData\Local\Temp\ipykernel_9144\718492628.py:11: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy accidentes_df.loc[:,'latitud'] = coorgeo[:,1]
Out[7]:
| num_expediente | fecha | hora | localizacion | numero | cod_distrito | distrito | tipo_accidente | estado_meteorológico | tipo_vehiculo | ... | rango_edad | sexo | cod_lesividad | lesividad | coordenada_x_utm | coordenada_y_utm | positiva_alcohol | positiva_droga | longitud | latitud | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | ... | De 30 a 34 años | Mujer | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN | -3.648245 | 40.383349 |
| 1 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | ... | De 35 a 39 años | Hombre | 7.0 | Asistencia sanitaria sólo en el lugar del acci... | 444976.463 | 4470508.259 | N | NaN | -3.648245 | 40.383349 |
| 2 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | ... | Desconocido | Desconocido | NaN | NaN | 444976.463 | 4470508.259 | N | NaN | -3.648245 | 40.383349 |
| 3 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | ... | De 10 a 14 años | Hombre | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN | -3.648245 | 40.383349 |
| 4 | 2020S019534 | 2021-01-01 | 04:30:00 | AVDA. PABLO NERUDA / CALL. LEONESES | 57 | 13.0 | PUENTE DE VALLECAS | Colisión fronto-lateral | Despejado | Turismo | ... | De 35 a 39 años | Mujer | 14.0 | Sin asistencia sanitaria | 444976.463 | 4470508.259 | N | NaN | -3.648245 | 40.383349 |
5 rows × 21 columns
Selección de registros base de datos¶
In [8]:
print(accidentes_df["tipo_persona"].unique())
['Conductor' 'Pasajero' 'Peatón' nan]
In [9]:
# Crear una nueva Dataframe que cumple las condiciones establecidas
acci_df=accidentes_df.loc[(accidentes_df['tipo_persona']=='Conductor')]
# si quisieramos introduccir más condicionantes --- & (accidentes_df['tipo_vehiculo']=='Turismo')& (accidentes_df['rango_edad']=='De 18 a 20 años')]
Mapa Puntual (MarkerCluster)
Los mapas puntuales permiten plasmar variables georeferenciadas, para un mejor entendimiento por parte del usuario de la distribucción de los mismas.
Diferentes plugins de Folium: https://python-visualization.github.io/folium/plugins.html
Iconos con prefijo 'fa': https://fontawesome.com/v5.15/icons?d=gallery&p=2&m=free
In [10]:
print(accidentes_df["tipo_vehiculo"].unique())
['Turismo' 'Autobús' 'Motocicleta hasta 125cc' 'Todo terreno' 'Bicicleta' 'Motocicleta > 125cc' 'Furgoneta' 'Camión rígido' 'Sin especificar' 'Ciclomotor' 'Maquinaria de obras' 'Tractocamión' 'Otros vehículos con motor' 'VMU eléctrico' 'Cuadriciclo no ligero' 'Vehículo articulado' 'Autocaravana' 'Bicicleta EPAC (pedaleo asistido)' 'Autobús articulado' 'Autobus EMT' 'Ambulancia SAMUR' 'Cuadriciclo ligero' 'Patinete' 'Ciclomotor de tres ruedas' 'Semiremolque' 'Moto de tres ruedas > 125cc' 'Ciclo' 'Maquinaria agrícola' 'Remolque' 'Moto de tres ruedas hasta 125cc' 'Ciclomotor de dos ruedas L1e-B' 'Tren/metro' 'Otros vehículos sin motor' 'Camión de bomberos' 'Ciclo de motor L1e-A' 'Tranvía' 'Autobús articulado EMT' nan]
In [11]:
# Crear el mapa base donde representar
mapa_accidentes = folium.Map(location=(40.43,-3.65), tiles = 'OpenStreetMap', zoom_start = 12)
# Crear diferentes dataframes
coche_df=acci_df.loc[(acci_df['tipo_vehiculo']=='Turismo')]
bici_df=acci_df.loc[(acci_df['tipo_vehiculo']=='Bicicleta')]
# crear un objeto de grupo de marcas para los incidentes en el DataFrame
coches = plugins.MarkerCluster( name="Accidentes_coche",).add_to(mapa_accidentes)
bicis = plugins.MarkerCluster( name="Accidentes_bicis",).add_to(mapa_accidentes)
# procesar el DataFrame y agregar cada punto de datos al grupo de marcas creado anteriormente
for lat, lng, label, in zip(coche_df.latitud, coche_df.longitud, coche_df['num_expediente']): #dos formas diferentes de llamar a un campo
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="orange", icon="car", prefix = 'fa'),
popup=label,
).add_to(coches)
for lat, lng, label, in zip(bici_df.latitud, bici_df.longitud, bici_df['num_expediente']): #dos formas diferentes de llamar a un campo
folium.Marker(
location=[lat, lng],
icon=folium.Icon(color="blue", icon="bicycle", prefix = 'fa'),
popup=label,
).add_to(bicis)
#Añadir controles
folium.LayerControl().add_to(mapa_accidentes)
draw = plugins.Draw(export=True)
draw.add_to(mapa_accidentes)
#Muestra mapa
mapa_accidentes
Out[11]:
Make this Notebook Trusted to load map: File -> Trust Notebook
